package com.syntaxtree.trees;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;

import com.syntaxtree.constant.ModifierCharacter;
import com.syntaxtree.constant.Other;
import com.syntaxtree.constant.Visibility;

public class FunctionTree extends BaseTree{
	public String FunctionName;
	public String FunctionVisibility;
	public boolean IsFinal;
	public boolean IsStatic;
	public boolean IsSynchronized;
	public boolean IsNative;
	public boolean IsStrictfp;
	public List<String> FunctionThrows = new ArrayList<String>();
	public HashMap<String, String> FunctionParams = new HashMap<String, String>();
	public String FunctionBody;
	public String FunctionHeader;

	public FunctionTree(String funcCode) {
		super(funcCode);
		initLocalVariable();
	}

	private void initLocalVariable() {
		this.FunctionHeader = getFunctionHeader(this.Code);
		this.FunctionBody = getFunctionBody(this.Code);
		this.FunctionName = getFunctionName(this.Code);
		this.FunctionParams = getFunctionParams(this.Code);
		this.FunctionThrows = getFunctionThrows(this.Code);
		String[] split = headerSplit(this.Code);
		this.FunctionVisibility = Visibility.PRIVATE;
		this.IsStatic = false;
		this.IsFinal = false;
		this.IsNative = false;
		this.IsSynchronized = false;
		this.IsStrictfp=false;
		for (int i = 0; i < split.length; i++) {
			if (split[i].equals(Visibility.PUBLIC))
				this.FunctionVisibility = Visibility.PUBLIC;
			if (split[i].equals(Visibility.PRIVATE))
				this.FunctionVisibility = Visibility.PRIVATE;
			if (split[i].equals(Visibility.PROTECTED))
				this.FunctionVisibility = Visibility.PROTECTED;
			if (split[i].equals(Visibility.DEFAULT))
				this.FunctionVisibility = Visibility.DEFAULT;
			if (split[i].equals(ModifierCharacter.STATIC))
				this.IsStatic = true;
			if (split[i].equals(ModifierCharacter.FINAL))
				this.IsFinal = true;
			if (split[i].equals(ModifierCharacter.NATIVE))
				this.IsNative = true;
			if (split[i].equals(ModifierCharacter.SYNCHRONIZED))
				this.IsSynchronized = true;
			if (split[i].equals(ModifierCharacter.STRICTFP))
				this.IsStrictfp = true;
		}
	}

	private String getFunctionHeader(String funcCode) {
		return funcCode.substring(0, funcCode.indexOf(')') + 1);
	}

	private String getFunctionBody(String funcCode) {
		return funcCode.substring(funcCode.indexOf('{'));
	}

	private List<String> getFunctionThrows(String funcCode) {
		String throwsStr = funcCode.substring(funcCode.indexOf(')') + 1, funcCode.indexOf('{'))
				.replace(ModifierCharacter.THROWS, Other.Empty).replaceAll("\s+", Other.Empty);
		List<String> throwsList = new ArrayList<String>();
		if (!throwsStr.isEmpty()) {
			String[] split = throwsStr.split(",");
			for (int i = 0; i < split.length; i++) {
				throwsList.add(split[i]);
			}
		}
		return throwsList;
	}

	private HashMap<String, String> getFunctionParams(String funcCode) {
		String functionHeader = getFunctionHeader(funcCode);
		String subParamsStr = functionHeader.substring(functionHeader.indexOf('(') + 1, functionHeader.indexOf(')'));
		HashMap<String, String> hashMap = new HashMap<String, String>();
		if (subParamsStr.isEmpty())
			return hashMap;
		String[] params = subParamsStr.split(",");
		for (int i = 0; i < params.length; i++) {
			if (params[i].contains("...")) {
				String[] tempSplit = params[i].split("\\.\\.\\.");
				hashMap.put(tempSplit[1].trim(), tempSplit[0].trim().concat("..."));
			} else if (params[i].contains("[")) {
				String[] tempSplit = params[i].split("\\[");
				hashMap.put(tempSplit[1].replace("]", Other.Empty).trim(), tempSplit[0].trim().concat("[]"));
			} else {
				String[] tempSplit = params[i].split(" ");
				hashMap.put(tempSplit[1].trim(), tempSplit[0].trim());
			}
		}
		return hashMap;
	}

	private String getFunctionName(String funcCode) {
		String[] split = headerSplit(funcCode);
		return split[split.length - 1];
	}

	private String[] headerSplit(String funcCode) {
		String functionHeader = getFunctionHeader(funcCode);
		String functionHeaderNotParam = functionHeader.substring(0, functionHeader.indexOf('('));
		String[] split = functionHeaderNotParam.split(" ");
		if (split.length < 2)
			throw new IllegalArgumentException(String.format("函数头(%s)异常", functionHeaderNotParam));
		return split;
	}

	public void showInfo() {
		System.out.println(String.format("源代码:%s", this.Code));
		System.out.println(String.format("函数名:%s", this.FunctionName));
		System.out.println(String.format("函数可见性:%s", this.FunctionVisibility));
		System.out.println(String.format("函数头:%s", this.FunctionHeader));
		System.out.println(String.format("函数体:%s", this.FunctionBody));
		ArrayList<String> list = new ArrayList<String>();
		for (Entry<String, String> entry : this.FunctionParams.entrySet()) {
			list.add(String.format("[%s,%s]", entry.getKey(), entry.getValue()));
		}
		System.out.println(String.format("参数表:%s", String.join(",", list)));
		System.out.println(String.format("异常表:%s", String.join(",", this.FunctionThrows)));
		System.out.println(String.format("is static:%s", this.IsStatic));
		System.out.println(String.format("is final:%s", this.IsFinal));
		System.out.println(String.format("is native:%s", this.IsNative));
		System.out.println(String.format("is strictfp:%s", this.IsStrictfp));
		System.out.println(String.format("is synchronized:%s", this.IsSynchronized));
	}
}
